package com.jinsp.cameralibrary.camera;

import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaScannerConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.constraint.ConstraintLayout;
import android.text.TextUtils;
import android.util.Log;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.jinsp.cameralibrary.PermissionFragment;
import com.jinsp.cameralibrary.R;
import com.jinsp.cameralibrary.ShapeImageView;
import com.jinsp.cameralibrary.util.BitmapUtils;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

public class CameraFragment extends PermissionFragment implements View.OnClickListener, View.OnTouchListener {

    public static final String TAG = "CameraFragment";
    private static final String ARG_CAMERA_CONFIG = "camera_config";

    private final int DEFAULT_PREVIEW_WIDTH = 720;      //相机预览宽
    private final int DEFAULT_PREVIEW_HEIGHT = 1280;    //相机预览高
    private final int DEFAULT_SAVE_PHOTO_WIDTH = 720;   //保存图片宽
    private final int DEFAULT_SAVE_PHOTO_HEIGHT = 1280; //保存图片高
    private Size previewSize, photoSize;        //预览、图片大小

    private final int FLASH_STATE_CLOSE = 0;    //关闭闪光灯
    private final int FLASH_STATE_AUTO = 1;     //自动闪光灯
    private final int FLASH_STATE_OPEN = 2;     //开启闪光灯
    private final int FLASH_STATE_LIGHT = 3;    //照明

    private CameraConfigBean mCameraConfigBean;
    private boolean isGrantCameraPermission;
    private int currentCameraId;            //当前相机方向
    private TextureView cameraPreviewTextureView;
    private ImageView cameraRotationImageView;
    private ShapeImageView photoPreviewImageView;

    private CameraManager mCameraManager;
    private CameraDevice mCameraDevice;
    private CameraCharacteristics mCameraCharacteristics;
    private ImageReader mPreviewImageReader;
    private Handler mCameraBackgroundHandler;
    private HandlerThread mCameraHandlerThread;
    private CameraCaptureSession mCameraCaptureSession;
    private CaptureRequest.Builder mCaptureRequestBuilder;
    private int cameraSensorOrientation;        //摄像头方向
    private int displayOrientation;             //屏幕方向
    private ImageButton switchCameraImageButton;
    private SimpleDateFormat dateFormat;        //保存图标文件格式
    private ImageButton flashImageButton;
    private float twoFingerDownDistance;
    private int zoomLevel = 1;             //缩放等级
    private int displayHeightPixels;       //屏幕高度
    private RelativeLayout cameraBottomFunctionRelativeLayout;
    private RelativeLayout cameraTopBottomFunctionRelativeLayout;
    private boolean isRotationAnimRunning;
    private ObjectAnimator rotationAnimator;
    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
    private int currentFlashState = FLASH_STATE_CLOSE;
    private ImageReader photoImageReader;

    public CameraFragment() {
        // Required empty public constructor
    }

    public static CameraFragment newInstance(CameraConfigBean cameraConfigBean) {
        CameraFragment fragment = new CameraFragment();
        Bundle args = new Bundle();
        args.putParcelable(ARG_CAMERA_CONFIG, cameraConfigBean);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mCameraConfigBean = getArguments().getParcelable(ARG_CAMERA_CONFIG);
        }
    }

    @Override
    public String[] getPermissions() {
        return new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE};
    }

    @Override
    public void onPermissionGrantSuccess() {
        isGrantCameraPermission = true;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View cameraView = inflater.inflate(R.layout.fragment_camera, container, false);
        cameraRotationImageView = cameraView.findViewById(R.id.iv_camera_switch);
        photoPreviewImageView = cameraView.findViewById(R.id.iv_camera_photo_preview);
        photoPreviewImageView.setBorderColor(Color.WHITE);
        photoPreviewImageView.setShape(ShapeImageView.SHAPE_CIRCLE);
        photoPreviewImageView.setBorderWidth(8);
        photoPreviewImageView.setOnClickListener(this);
        cameraBottomFunctionRelativeLayout = cameraView.findViewById(R.id.rl_camera_bottom_function);
        cameraTopBottomFunctionRelativeLayout = cameraView.findViewById(R.id.rl_camera_top_function);
        cameraPreviewTextureView = cameraView.findViewById(R.id.camera_preview);
        cameraView.setBackgroundColor(mCameraConfigBean.getCameraPreviewBackgroundColor());
        if (mCameraConfigBean.getTakePhotoButtonDrawableId() != 0) {
            ImageButton takePhotoImageButton = cameraView.findViewById(R.id.ib_camera_take_photo);
            takePhotoImageButton.setImageDrawable(getResources().getDrawable(mCameraConfigBean.getTakePhotoButtonDrawableId()));
            takePhotoImageButton.setOnClickListener(this);
        }
        if (mCameraConfigBean.getSwitchCameraDrawableId() != 0) {
            switchCameraImageButton = cameraView.findViewById(R.id.ib_camera_switch);
            switchCameraImageButton.setImageDrawable(getResources().getDrawable(mCameraConfigBean.getSwitchCameraDrawableId()));
            switchCameraImageButton.setOnClickListener(this);
        }
        flashImageButton = cameraView.findViewById(R.id.ib_camera_flash);
        flashImageButton.setOnClickListener(this);
        if (mCameraConfigBean.getCloseFlashDrawableId() != 0) {
            //默认不使用闪光灯
            flashImageButton.setImageDrawable(getResources().getDrawable(mCameraConfigBean.getCloseFlashDrawableId()));
        }
        //设置预览区域大小
        setTextureViewSize();
        //摄像头默认方向
        currentCameraId = mCameraConfigBean.isDefaultFront() ? CameraCharacteristics.LENS_FACING_BACK
                : CameraCharacteristics.LENS_FACING_FRONT;
        init();
        return cameraView;
    }

    private void setTextureViewSize() {
        ViewGroup.LayoutParams layoutParams = cameraPreviewTextureView.getLayoutParams();
        int displayWidthPixels = getResources().getDisplayMetrics().widthPixels;
        displayHeightPixels = getResources().getDisplayMetrics().heightPixels;
        float displayRatio = 1.0f * displayWidthPixels / displayHeightPixels;
        Log.d(TAG, "获取屏幕分辨率: " + displayWidthPixels + "x" + displayHeightPixels + "，宽高比：" + displayRatio);
        if (mCameraConfigBean.getRatio() == CameraConfigBean.CAMERA_RATIO_4_3) {
            //3:4
            if (displayRatio != (3.0 / 4)) {
                layoutParams.width = displayWidthPixels;
                layoutParams.height = displayWidthPixels * 4 / 3;
                cameraPreviewTextureView.setLayoutParams(layoutParams);
                cameraRotationImageView.setLayoutParams(layoutParams);
            }
        } else {
            //9:16
            if (displayRatio != (9.0 / 16)) {
                layoutParams.width = displayWidthPixels;
                layoutParams.height = displayWidthPixels * 16 / 9;
                cameraPreviewTextureView.setLayoutParams(layoutParams);
                cameraRotationImageView.setLayoutParams(layoutParams);
            }
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    private void init() {
        if (!isGrantCameraPermission) {
            return;
        }
        //查看设备是否存在摄像头
        mCameraManager = (CameraManager) Objects.requireNonNull(getActivity()).getSystemService(Context.CAMERA_SERVICE);
        try {
            assert mCameraManager != null;
            String[] cameraIdList = mCameraManager.getCameraIdList();
            if (cameraIdList.length == 0) {
                Log.e(TAG, "相机不存在");
                getActivity().finish();
                return;
            } else if (cameraIdList.length == 1) {
                //仅有一个摄像头
                if (switchCameraImageButton != null) {
                    switchCameraImageButton.setVisibility(View.GONE);
                }
                String cameraId = cameraIdList[0];
                currentCameraId = Integer.parseInt(cameraId);
                if (cameraId.equals(String.valueOf(CameraCharacteristics.LENS_FACING_FRONT))) {
                    Log.d(TAG, "只存在前置相机");
                } else {
                    Log.d(TAG, "只存在后置相机");
                }
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        mCameraHandlerThread = new HandlerThread("CameraThread");
        mCameraHandlerThread.start();
        mCameraBackgroundHandler = new Handler(mCameraHandlerThread.getLooper());
        //监听TextureView回调
        cameraPreviewTextureView.setSurfaceTextureListener(surfaceTextureListener);
        cameraPreviewTextureView.setOnTouchListener(this);
        //预览以及图片大小
        previewSize = new Size(DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT);
        photoSize = new Size(DEFAULT_SAVE_PHOTO_WIDTH, DEFAULT_SAVE_PHOTO_HEIGHT);
        //创建文件存储
        if (!TextUtils.isEmpty(mCameraConfigBean.getPhotoStoragePath())) {
            File photoStorageFile = new File(mCameraConfigBean.getPhotoStoragePath());
            if (!photoStorageFile.exists()) {
                photoStorageFile.mkdirs();
            }
        }
        //文件名格式：年-月-日-时-分-秒
        dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
        //屏幕方向
        displayOrientation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
    }

    //TextureView状态回调
    private final TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            //设置上下功能区域高度
            setFunctionAreaHeight(width, height);
            openCamera();
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            stopCamera();
            return true;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {

        }
    };

    /**
     * 根据预览区域设置上下功能区域的高度
     *
     * @param width  TextureView宽度
     * @param height TextureView高度
     */
    private void setFunctionAreaHeight(int width, int height) {
        int translateHeight = dp2Px(15);    //平移高度
        //设置顶部功能区域宽高
        ViewGroup.LayoutParams topLayoutParams = cameraTopBottomFunctionRelativeLayout.getLayoutParams();
        topLayoutParams.width = width;
        int topFunctionHeight;
        if (mCameraConfigBean.getRatio() == CameraConfigBean.CAMERA_RATIO_16_9) {
            topFunctionHeight = dp2Px(60);
        } else {
            topFunctionHeight = cameraPreviewTextureView.getTop() - translateHeight;
            //移动预览区域
            ConstraintLayout.LayoutParams previewLayoutParams = (ConstraintLayout.LayoutParams) cameraPreviewTextureView.getLayoutParams();
            previewLayoutParams.topToBottom = R.id.rl_camera_top_function;
            previewLayoutParams.topToTop = -1;
            previewLayoutParams.bottomToBottom = -1;
            cameraPreviewTextureView.setLayoutParams(previewLayoutParams);
            cameraRotationImageView.setLayoutParams(previewLayoutParams);
        }
        Log.d(TAG, "顶部功能区域宽高: " + width + "x" + topFunctionHeight);
        topLayoutParams.height = topFunctionHeight;
        cameraTopBottomFunctionRelativeLayout.setLayoutParams(topLayoutParams);
        //设置底部拍照区域宽高
        ViewGroup.LayoutParams bottomLayoutParams = cameraBottomFunctionRelativeLayout.getLayoutParams();
        bottomLayoutParams.width = width;
        int bottomFunctionHeight;
        if (mCameraConfigBean.getRatio() == CameraConfigBean.CAMERA_RATIO_16_9) {
            bottomFunctionHeight = dp2Px(75);
        } else {
            bottomFunctionHeight = displayHeightPixels - height - cameraPreviewTextureView.getTop()
                    + translateHeight;
        }
        bottomLayoutParams.height = bottomFunctionHeight;
        Log.d(TAG, "底部拍照功能区域宽高：" + width + "x" + bottomFunctionHeight);
        cameraBottomFunctionRelativeLayout.setLayoutParams(bottomLayoutParams);
        if (mCameraConfigBean.getRatio() == CameraConfigBean.CAMERA_RATIO_16_9) {
            //全屏显示
            cameraTopBottomFunctionRelativeLayout.setBackgroundColor(Color.TRANSPARENT);
            cameraBottomFunctionRelativeLayout.setBackgroundColor(Color.TRANSPARENT);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        Objects.requireNonNull(getActivity()).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        if (cameraPreviewTextureView.isAvailable()) {
            openCamera();
        } else {
            cameraPreviewTextureView.setSurfaceTextureListener(surfaceTextureListener);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        Objects.requireNonNull(getActivity()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        stopCamera();
    }

    /**
     * 打开相机
     */
    @SuppressLint("MissingPermission")
    private void openCamera() {
        if (isGrantCameraPermission) {
            try {
                //获取指定摄像头参数
                mCameraCharacteristics = mCameraManager.getCameraCharacteristics(String.valueOf(currentCameraId));
                //是否支持闪光灯
                Boolean isSupportFlash = mCameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
                if (isSupportFlash == null || !isSupportFlash) {
                    flashImageButton.setVisibility(View.GONE);
                    Log.d(TAG, "相机不支持闪光灯");
                }
                //是否支持新特性
                Integer supportHardwareLevel = mCameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
                if (supportHardwareLevel == null || supportHardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
                    Log.d(TAG, "相机不支持新特性");
                }
                //获取摄像头方向
                Integer sensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
                if (sensorOrientation == null) {
                    cameraSensorOrientation = -1;
                } else {
                    cameraSensorOrientation = sensorOrientation;
                }
                //查看是否需要交换宽高
                boolean isNeedSwapWH = isNeedSwapWidthAndHeight();
                //获取相机支持的所有尺寸
                StreamConfigurationMap streamConfigurationMap = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                if (streamConfigurationMap != null) {
                    //获取支持的所有预览尺寸
                    Size[] cameraPreviewSupportSize = streamConfigurationMap.getOutputSizes(SurfaceTexture.class);
                    //获取支持的所有图片尺寸
                    Size[] cameraPhotoSupportSize = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
                    if (cameraPreviewSupportSize != null && cameraPhotoSupportSize != null) {
                        Log.d(TAG, "相机支持的预览尺寸: " + Arrays.toString(cameraPreviewSupportSize));
                        Log.d(TAG, "相机支持的图片尺寸: " + Arrays.toString(cameraPhotoSupportSize));
                        //寻找最佳的预览以及图片尺寸
                        previewSize = findBestSize(isNeedSwapWH, cameraPreviewSupportSize,
                                previewSize.getWidth(), previewSize.getHeight());
                        photoSize = findBestSize(isNeedSwapWH, cameraPhotoSupportSize,
                                photoSize.getWidth(), photoSize.getHeight());
                        Log.d(TAG, "计算后的最佳预览大小: " + previewSize);
                        Log.d(TAG, "计算后的最佳图片大小: " + photoSize);
                        //重新调整预览显示的宽高防止拉伸
                        cameraPreviewTextureView.getSurfaceTexture().setDefaultBufferSize(previewSize.getWidth(),
                                previewSize.getHeight());
                        /*ViewGroup.LayoutParams layoutParams = cameraPreviewTextureView.getLayoutParams();
                        if (displayOrientation == Configuration.ORIENTATION_LANDSCAPE) {
                            //横屏
                            layoutParams.width = previewSize.getWidth();
                            layoutParams.height = previewSize.getHeight();
                        } else {
                            //竖屏
                            layoutParams.width = previewSize.getHeight();
                            layoutParams.height = previewSize.getWidth();
                        }
                        cameraPreviewTextureView.setLayoutParams(layoutParams);*/
                        //设置预览帧格式数据
                        mPreviewImageReader = ImageReader.newInstance(previewSize.getWidth(),
                                previewSize.getHeight(), ImageFormat.YUV_420_888, 1);
                        mPreviewImageReader.setOnImageAvailableListener(this::createLatestBitmap, mCameraBackgroundHandler);
                        //设置保存拍照图片格式数据
                        photoImageReader = ImageReader.newInstance(photoSize.getWidth(),
                                photoSize.getHeight(), ImageFormat.JPEG, 1);
                        photoImageReader.setOnImageAvailableListener(this::savePhoto, mCameraBackgroundHandler);
                        //开启相机预览
                        mCameraManager.openCamera(String.valueOf(currentCameraId), cameraStateCallback,
                                mCameraBackgroundHandler);
                    }
                }
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取最后一帧的预览数据bitmap
     *
     * @param reader 预览帧数据
     */
    private void createLatestBitmap(ImageReader reader) {
        //获取最后一帧数据
        Image image = reader.acquireLatestImage();
        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] yuvBytes = new byte[buffer.remaining()];
        buffer.get(yuvBytes);
        image.close();
        //转换bitmap以便切换相机时使用
        YuvImage yuvImage = new YuvImage(yuvBytes, ImageFormat.YUY2,
                previewSize.getWidth(), previewSize.getHeight(), null);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()),
                100, outputStream);
        Bitmap latestPreviewBitmap = BitmapFactory.decodeByteArray(outputStream.toByteArray(),
                0, outputStream.size());
        if (latestPreviewBitmap != null) {
            Bitmap blurPreviewBitmap = BitmapUtils.startBlur(getContext(), latestPreviewBitmap, 25);
            if (blurPreviewBitmap != null) {
                mMainHandler.post(() -> {
                    cameraRotationImageView.setImageBitmap(BitmapUtils.rotateBitmap(blurPreviewBitmap, -90));
                    stopCamera();
                    startAnim();
                });
            }
        }
    }

    /**
     * 保存拍摄的图片
     *
     * @param reader 图片数据
     */
    private void savePhoto(ImageReader reader) {
        mCameraBackgroundHandler.post(() -> {
            File photoFile = new File(mCameraConfigBean.getPhotoStoragePath() + File.separator
                    + dateFormat.format(new Date()) + ".jpg");
            Image image = reader.acquireLatestImage();
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            BufferedOutputStream outputStream = null;
            try {
                outputStream = new BufferedOutputStream(new FileOutputStream(photoFile));
                outputStream.write(bytes);
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                image.close();
                try {
                    if (outputStream != null) {
                        outputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                //刷新文件系统
                refreshFile(photoFile);
            }
            //显示预览缩略图
            showPreviewPhoto(photoFile);
        });
    }

    /**
     * 读取拍照文件并显示缩略图
     *
     * @param photoFile 拍照图片
     */
    private void showPreviewPhoto(File photoFile) {
        mMainHandler.post(() -> {
            if (photoFile.exists()) {
                if (photoPreviewImageView.getVisibility() == View.GONE) {
                    photoPreviewImageView.setVisibility(View.VISIBLE);
                }
                photoPreviewImageView.setImageBitmap(BitmapFactory.decodeFile(photoFile.getAbsolutePath()));
            }
        });
    }

    //相机开启状态回调
    private final CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            mCameraDevice = camera;
            try {
                //创建预览请求
                mCaptureRequestBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                Surface surface = new Surface(cameraPreviewTextureView.getSurfaceTexture());
                mCaptureRequestBuilder.addTarget(surface);
//                mCaptureRequestBuilder.addTarget(mPreviewImageReader.getSurface());
                //自动对焦
                mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                //创建预览会话
                camera.createCaptureSession(Arrays.asList(surface, mPreviewImageReader.getSurface(),
                        photoImageReader.getSurface()),
                        captureSessionStateCallback, mCameraBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            camera.close();
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            Log.e(TAG, "相机开启失败: " + error);
            camera.close();
        }
    };

    //预览会话状态回调
    private final CameraCaptureSession.StateCallback captureSessionStateCallback = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
            mCameraCaptureSession = session;
            try {
                session.setRepeatingRequest(mCaptureRequestBuilder.build(),
                        captureCallback, mCameraBackgroundHandler);
                mMainHandler.postDelayed(() -> {
                    cameraRotationImageView.setVisibility(View.GONE);
                    cameraPreviewTextureView.setVisibility(View.VISIBLE);
                }, 600);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
            stopCamera();
            Log.e(TAG, "预览失败");
        }
    };

    //预览图像捕捉回调
    private final CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                       @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
        }

        @Override
        public void onCaptureFailed(@NonNull CameraCaptureSession session,
                                    @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
            Log.e(TAG, "相机预览失败: ");
        }
    };

    /**
     * 寻找最佳尺寸大小
     *
     * @param isNeedSwapWH 是否需要交换宽高
     * @param supportSize  相机支持的所有尺寸
     * @param width        原始的宽
     * @param height       原始的高
     * @return 最佳大小
     */
    private Size findBestSize(boolean isNeedSwapWH, Size[] supportSize, int width, int height) {
        int maxWidth = cameraPreviewTextureView.getWidth();     //最大的宽
        int maxHeight = cameraPreviewTextureView.getHeight();   //最大的高
        int realWidth = width;    //实际的宽
        int realHeight = height;  //实际的高
        if (isNeedSwapWH) {
            realWidth = height;
            realHeight = width;
            maxWidth = cameraPreviewTextureView.getHeight();
            maxHeight = cameraPreviewTextureView.getWidth();
        }
        //存储与指定大小比较后的大小
        List<Size> bigSizeList = new ArrayList<>();
        List<Size> smallSizeList = new ArrayList<>();
        for (Size size : supportSize) {
            if (size.getWidth() <= maxWidth && size.getHeight() <= maxHeight
                    && size.getWidth() == size.getHeight() * realWidth / realHeight) {
                if (size.getWidth() >= realWidth && size.getHeight() >= realHeight) {
                    bigSizeList.add(size);
                } else {
                    smallSizeList.add(size);
                }
            }
        }
        if (bigSizeList.size() > 0) {
            //寻找大于指定尺寸中的最小值
            return Collections.min(bigSizeList, new CompareSizes());
        } else if (smallSizeList.size() > 0) {
            //寻找小于指定尺寸的最大值
            return Collections.max(smallSizeList, new CompareSizes());
        } else {
            return supportSize[0];
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getPointerCount() == 1) {
            //单指对焦
        } else if (event.getPointerCount() == 2) {
            //双指处理缩放
            int action = event.getAction() & MotionEvent.ACTION_MASK;
            if (action == MotionEvent.ACTION_POINTER_DOWN) {
                twoFingerDownDistance = getFingerSpacing(event);
            } else if (action == MotionEvent.ACTION_MOVE) {
                float twoFingerMoveDistance = getFingerSpacing(event);
                startScale(twoFingerMoveDistance > twoFingerDownDistance);
                twoFingerDownDistance = twoFingerMoveDistance;
            }
        }
        return true;
    }

    /**
     * 预览缩放
     *
     * @param isZoom true -- 放大
     */
    private void startScale(boolean isZoom) {
        //获取支持最大的缩放等级
        Float supportMaxZoom = mCameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
        if (supportMaxZoom != null) {
            float maxZoom = supportMaxZoom * 10;
            //获取缩放区域
            Rect rect = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
            if (rect != null) {
                if (isZoom && maxZoom > zoomLevel) {
                    zoomLevel++;
                } else if (zoomLevel > 1) {
                    zoomLevel--;
                }
                //计算缩放比例并计算裁剪区域
                int minW = (int) (rect.width() / maxZoom);
                int minH = (int) (rect.height() / maxZoom);
                int difW = rect.width() - minW;
                int difH = rect.height() - minH;
                int cropW = difW / 100 * zoomLevel;
                int cropH = difH / 100 * zoomLevel;
                cropW -= cropW & 3;
                cropH -= cropH & 3;
                Rect zoomRect = new Rect(cropW, cropH, rect.width() - cropW, rect.height() - cropH);
                mCaptureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoomRect);
                //更新预览请求
                try {
                    mCameraCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(),
                            captureCallback, mCameraBackgroundHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 计算两指的间距，实现缩放
     *
     * @param event 滑动事件
     * @return 移动的间距
     */
    private float getFingerSpacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return (float) Math.sqrt(x * x + y * y);
    }

    //为Size定义一个比较器Comparator
    private static class CompareSizes implements Comparator<Size> {
        @Override
        public int compare(Size beforeSize, Size afterSize) {
            //强转为long保证不会发生溢出
            return Long.signum((long) beforeSize.getWidth() * beforeSize.getHeight() -
                    (long) afterSize.getWidth() * afterSize.getHeight());
        }
    }

    /**
     * 根据屏幕方向以及相机方向检查是否需要交换显示区域的宽高
     *
     * @return true -- 需要交换宽高
     */
    private boolean isNeedSwapWidthAndHeight() {
        Log.d(TAG, "屏幕方向: " + displayOrientation + "，相机方向：" + cameraSensorOrientation);
        boolean isNeedSwap = false;
        switch (displayOrientation) {
            case Surface.ROTATION_0:
            case Surface.ROTATION_180: {
                //竖屏
                isNeedSwap = (cameraSensorOrientation == 90 || cameraSensorOrientation == 270);
            }
            break;
            case Surface.ROTATION_90:
            case Surface.ROTATION_270: {
                //横屏
                isNeedSwap = (cameraSensorOrientation == 0 || cameraSensorOrientation == 180);
            }
            break;
            default:
                break;
        }
        return isNeedSwap;
    }

    /**
     * 关闭相机
     */
    private void stopCamera() {
        if (isGrantCameraPermission) {
            if (rotationAnimator != null && rotationAnimator.isRunning()) {
                rotationAnimator.cancel();
                rotationAnimator = null;
            }
            if (mPreviewImageReader != null) {
                mPreviewImageReader.close();
                mPreviewImageReader = null;
            }
            if (mCameraCaptureSession != null) {
                mCameraCaptureSession.close();
                mCameraCaptureSession = null;
            }
            if (mCameraDevice != null) {
                mCameraDevice.close();
                mCameraDevice = null;
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mCameraHandlerThread != null) {
            mCameraHandlerThread.quit();
            mCameraHandlerThread = null;
        }
        mMainHandler.removeCallbacksAndMessages(null);
    }

    @Override
    public void onClick(View v) {
        if (isRotationAnimRunning) {
            return;
        }
        int id = v.getId();
        if (id == R.id.ib_camera_take_photo) {
            takePhoto();
        } else if (id == R.id.ib_camera_switch) {
            switchCamera();
        } else if (id == R.id.iv_camera_photo_preview) {

        } else if (id == R.id.ib_camera_flash) {
            switchFlash();
        }
    }

    /**
     * 切换闪光灯
     */
    private void switchFlash() {

    }

    /**
     * 照明控制
     *
     * @param isContinuously true -- 开启照明
     */
    private void light(boolean isContinuously) {
        mCaptureRequestBuilder.set(CaptureRequest.FLASH_MODE, isContinuously ? CaptureRequest.FLASH_MODE_TORCH
                : CaptureRequest.FLASH_MODE_OFF);
        try {
            mCameraCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(),
                    captureCallback, mCameraBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 拍照
     */
    private void takePhoto() {
        if (mCameraDevice == null || !cameraPreviewTextureView.isAvailable()) {
            return;
        }
        try {
            CaptureRequest.Builder takePhotoRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            //根据相机方向对图片进行旋转
            takePhotoRequest.set(CaptureRequest.JPEG_ORIENTATION, cameraSensorOrientation);
            takePhotoRequest.addTarget(photoImageReader.getSurface());
            takePhotoRequest.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            if (currentFlashState == FLASH_STATE_AUTO) {
                takePhotoRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            } else if (currentFlashState == FLASH_STATE_OPEN) {
                takePhotoRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
            }
            mCameraCaptureSession.capture(takePhotoRequest.build(), null, mCameraBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 切换相机
     */
    private void switchCamera() {
        if (mCameraDevice == null || !cameraPreviewTextureView.isAvailable()) {
            return;
        }
        //捕捉最后一帧预览图数据
        try {
            mCaptureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, cameraSensorOrientation);
            mCaptureRequestBuilder.addTarget(mPreviewImageReader.getSurface());
            mCameraCaptureSession.capture(mCaptureRequestBuilder.build(), null, mCameraBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        //切换前后置摄像头
        if (currentCameraId == CameraCharacteristics.LENS_FACING_FRONT) {
            //切换前置
            currentCameraId = CameraCharacteristics.LENS_FACING_BACK;
        } else {
            //切换后置
            currentCameraId = CameraCharacteristics.LENS_FACING_FRONT;
        }
        /*stopCamera();
        //切换动画
        startAnim();*/
    }

    private void startAnim() {
        if (rotationAnimator == null) {
            rotationAnimator = ObjectAnimator.ofFloat(cameraRotationImageView,
                    "rotationY", 0, 180);
            rotationAnimator.setDuration(300);
            rotationAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    isRotationAnimRunning = false;
                    openCamera();
                }

                @Override
                public void onAnimationStart(Animator animation) {
                    cameraRotationImageView.setVisibility(View.VISIBLE);
                    cameraPreviewTextureView.setVisibility(View.INVISIBLE);
                    isRotationAnimRunning = true;
                }
            });
            rotationAnimator.start();
        } else {
            rotationAnimator.reverse();
        }
    }

    /**
     * 通知系统扫描指定文件
     *
     * @param file 待刷新的文件
     */
    private void refreshFile(File file) {
        MediaScannerConnection.scanFile(getContext(),
                new String[]{file.getAbsolutePath()}, null, null);
    }

    /**
     * dp转px
     *
     * @param dpValue dp值
     * @return 转换后的px值
     */
    private int dp2Px(float dpValue) {
        float scale = getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
}